const _cache: Record<string | symbol, () => any> = {}

export function singleton<T>(identity: string | symbol, task: () => T): T {
    if (typeof identity !== 'string' && typeof identity !== 'symbol') {
        throw new Error('invalid identity')
    }
    const cache = _cache[identity]
    if (typeof cache === 'function') {
        return cache()
    }

    const result = task()
    if (result instanceof Promise) {
        _cache[identity] = () => result
        result.finally(() => {
            delete _cache[identity]
        })
    }

    return result
}
